package com.servlet.model.algorithmes;

import java.io.Serializable;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.TreeSet;

import com.listener.ContextListener;
import com.servlet.model.base.Administrator;
import com.servlet.model.base.Area;
import com.servlet.model.base.Experience;
import com.servlet.model.base.Profile;
import com.servlet.model.base.Study;
import com.servlet.model.database.BaseAcces;

/**
 * Classe de comparaisons de profils, permet de déceler les similitudes entre les contacts
 * @author Marc Bouffard
 */
public class AccountComparator<T> implements Comparator<Profile> , Serializable
{
	
	private double studiesCoeficient;
	private double experiencesCoeficient;
	private double profileCoeficient;
	
	public int compare(Profile p0, Profile p1 )
	{
		if( p0.getNiveau() < p1.getNiveau() )
		{
			return 1;
		}
		else if( p0.getNiveau() > p1.getNiveau() )
		{
			return -1;
		}
		
		if( p0.getProx() > p1.getProx() )
		{
			return 1;
		}
		else
		{
			return -1;
		}
	}

	public AccountComparator()
	{
		//base.
		Administrator a = ContextListener.base.findAdmin();
		
		if( a != null )
		{
			studiesCoeficient = a.getCoefStudy();
			experiencesCoeficient = a.getCoefPro();
			profileCoeficient = a.getCoefStudy();
		}
		else
		{
			studiesCoeficient = 1;
			experiencesCoeficient = 1;
			profileCoeficient = 1;
		}
	}
	
	/**
	 * Lance la comparaison entre deux profil :
	 * on détecte trois types de similitudes :
	 * - selon les études
	 * - selon les expériences
	 * - selon l'âge et la localisation
	 * Chacune de ces similitudes est pondérée par un coefficient
	 * @param login1
	 * @param login2
	 * @return une valeur de similitude, plus elle est élevée, plus les contacts sont proches
	 */
	public double accountComparaison(String login1, String login2)
	{
		double sum = 0;
		
		sum += studiesComparaison(login1, login2) * studiesCoeficient;
		sum += experiencesComparaison(login1, login2) * experiencesCoeficient;
		sum += profileComparaison(login1, login2) * profileCoeficient;

		return sum;
	}

	/**
	 * Comparaison de deux profils selon les études
	 * @param email1
	 * @param email2
	 * @return plus les deux profils ont des études communes plus la valeur de retour est grande
	 */
	private double studiesComparaison(String email1, String email2)
	{
		ArrayList<Study> s1 = ContextListener.base.findStudies(email1);
		ArrayList<Study> s2 = ContextListener.base.findStudies(email2);
		
		double sum = 0;
		
		TreeSet<Double> order = new TreeSet<Double>();

		for( int i = 0 ; i < s1.size() ; i++ )
		{
			for( int j = 0 ; j < s2.size() ; j++ )
			{
				order.add( studieComparaison(s1.get(i), s2.get(j)) );
			}
		}

		Double[] ares = order.toArray(new Double[0]);
		
		for( int i = 0 ; i < Math.min(ares.length , 10 ) ; i++ )
		{
			sum += ares[i];
		}
		return sum;
	}

	/**
	 * Comparaison de deux profils selon leurs expériences respectives
	 * @param email1
	 * @param email2
	 * @return plus les deux profils ont des expériences dans des entreprises similaires plus la valeur de retour est grande
	 */
	private double experiencesComparaison(String email1, String email2)
	{
		ArrayList<Experience> s1 = ContextListener.base.findExperiences(email1);
		ArrayList<Experience> s2 = ContextListener.base.findExperiences(email2);
		
		double sum = 0;
		
		TreeSet<Double> order = new TreeSet<Double>();
		
		for( int i = 0 ; i < s1.size() ; i++ )
		{
			for( int j = 0 ; j < s2.size() ; j++ )
			{
				order.add( experienceComparaison(s1.get(i), s2.get(j)) );
			}
		}
		
		Double[] ares = order.toArray(new Double[0]);
		
		for( int i = 0 ; i < Math.min(ares.length , 10 ) ; i++ )
		{
			sum += ares[i];
		}
		
		return sum;
	}
	
	/**
	 * Comparaison de deux profils selon leurs âges et localisations respectives
	 * @param email1
	 * @param email2
	 * @return plus les deux profils ont un âge et une localisation proche plus la valeur de retour est grande
	 */
	private double profileComparaison(String email1, String email2)
	{
		Profile p1 = ContextListener.base.findProfile(email1);
		Profile p2 = ContextListener.base.findProfile(email1);
		
		long year = 1000 * 60 * 60 * 24 * 365;
		long ecart = year * 2;
		double sum = 0;
		
		
		if( p1.getBirth_date() != null && p2.getBirth_date() != null )
		{
			if( p1.getBirth_date().getTime() + ecart > p2.getBirth_date().getTime() && p1.getBirth_date().getTime() - ecart < p2.getBirth_date().getTime() )
			{
				sum += 10;
			}
		}
		
		if( p1.getWorldArea() != null && p1.getWorldArea()!= Area.areaVide && p2.getWorldArea() != null && p2.getWorldArea()!= Area.areaVide )
		{
			if( p1.getWorldArea().getCountry().compareTo( p2.getWorldArea().getCountry() ) == 0 )
			{
				sum += 15;
				
				if( p1.getWorldArea().getCity_code() == p2.getWorldArea().getCity_code() )
				{
					sum += 25;
				}
			}
		}
		
		
		return sum;

	}

	/**
	 * Comparaison de deux expériences
	 * @param email1
	 * @param email2
	 * @return une valeur d'autant plus grandes que les expériences sont similaires
	 */
	private Double experienceComparaison(Experience ex1, Experience ex2)
	{
		double sum = 0;
		
		sum += dateCoincidente( ex1.getDateBegin() , ex1.getDateEnd() , ex2.getDateBegin() , ex2.getDateEnd() );
		
		sum += areaCoincidente( ex1.getArea() , ex2.getArea() );
		
		if( ex1.getPost().compareTo( ex2.getPost() ) == 0 )
		{
			sum += 10;
		}
		
		if( ex1.getActivityDomain().getSector() == ex2.getActivityDomain().getSector() )
		{
			sum += 10;
		}
		
		if( ex1.getEnterprise().compareTo( ex2.getEnterprise() ) == 0 )
		{
			sum += 10;
		}
		
		return sum;
	}
	
	/**
	 * Comparaison de deux zones
	 * @param email1
	 * @param email2
	 * @return une valeur grande si les zones sont identiques, 0 sinon
	 */
	private double areaCoincidente(Area area, Area area2)
	{
		double sum = 0;
		
		if( area.getCountry().compareTo( area2.getCountry() ) == 0 )
		{
			sum += 15;
			
			if( area.getCity_code() == area2.getCity_code() )
			{
				sum += 25;
			}
		}
		return sum;
	}

	/**
	 * Comparaison de deux études
	 * @param email1
	 * @param email2
	 * @return 0 si rien en commun, augmente si école ou spécialité commune
	 */
	private Double studieComparaison(Study s1, Study s2)
	{
		double sum = 0;
		
		sum += dateCoincidente( s1.getDateBegin() , s1.getDateEnd() , s2.getDateBegin() , s2.getDateEnd() );
		
		sum += areaCoincidente( s1.getArea() , s2.getArea() );
		
		if( s1.getSchool().compareTo( s2.getSchool() ) == 0 )
		{
			sum += 10;
		}
		
		if( s1.getMajor().compareTo( s2.getMajor() ) == 0 )
		{
			sum += 10;
		}
		
		return sum;
	}

	
	private double dateCoincidente(Date db1 , Date de1 , Date db2, Date de2)
	{
		if( db1.before(db2) && de1.after(db2) ||
			db1.before(de2) && de1.after(de2)	)
		{
			return 15;
		}
	
		return 0;
	}

}
